import gdb

def is_container(v):
    c = v.code
    return (c == gdb.TYPE_CODE_STRUCT or c == gdb.TYPE_CODE_UNION)

class PrintStruct(gdb.Command):
    """print fields of a struct: print-struct STRUCT-NAME
Iterate through the fields of a struct, and display
a human-readable form of the objects."""

    def __init__(self):
        super(PrintStruct, self).__init__(
            'print-struct',
            gdb.COMMAND_DATA, gdb.COMPLETE_SYMBOL, False)


    def invoke(self, arg, from_tty):
        argv = gdb.string_to_argv(arg)
        if len(argv) != 1:
            raise gdb.GdbError('print-struct STRUCT-NAME.')
        
        name = argv[0]
        try:
            t = gdb.lookup_type(name)
        except RuntimeError:
            print ("type %s not found" % name)
            return
        
        if is_container(t):
            gdb.write('%s\n{\n' % (name,))
            self._print_fields(name, t, 0)
            gdb.write('},\n')
        else:
            print ("Found no struct")
        
    def _print_fields(self, n, typeobject, indent=0):
        size = typeobject.sizeof
        off_width = len(str(size)) + 2

        indent += 4
        next_indent = indent + off_width

        indent_str = ' ' * indent
        next_indent_str = ' ' * next_indent

        flds = typeobject.fields()
        for x in flds:
            if is_container(x.type):
                sm = '%s' % x.type
                st = gdb.lookup_type(sm)

                offset_str = '[%d]'%(x.bitpos//8)
                offset_str=offset_str.ljust(off_width, ' ')

                gdb.write('%s%s%s\n' % (indent_str,offset_str,sm))
                gdb.write('%s{\n'%next_indent_str)
                self._print_fields(sm, x.type, next_indent)
                gdb.write('%s}%s:%d,\n' % (next_indent_str,x.name,x.type.sizeof))
            else:
                offset_str = '[%d]'%(x.bitpos//8)
                offset_str=offset_str.ljust(off_width, ' ')
                gdb.write('%s%s%s:%d,\n' % (indent_str,offset_str,x.name,x.type.sizeof))
PrintStruct()